package org.example.tomcat;

import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;


//已完成分发请求的功能 TODO 监听机制和 过滤器机制 再看看看其他核心机制 简单实现即可
public class Tomcat {



    public static void main(String[] args) {
        Tomcat tomcat = new Tomcat();
        tomcat.deployApps();
        
        tomcat.start();

    }



    //装载servlet 当前文件夹的  所以是目录要递归
    public void deployApps() {
        //把webapps 目录下的所有.servlet文件加载到内存中
        File webapps = new File("webapps");
        deployAppOut(webapps, "");

        //把当前包的所有.servlet文件加载到内存中
        deployAppIn("org.example.tomcat.servlets");

    }


    // 加载包下的所有servlet文件
    private void deployAppIn(String path) {
        try {
            // 获取当前线程的上下文类加载器
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

            // 将包名转换为文件系统路径
            String packagePath = path.replace('.', '/');
            URL packageUrl = classLoader.getResource(packagePath);

            if (packageUrl != null) {
                if (packageUrl.getProtocol().equals("file")) {
                    // 处理文件系统路径
                    File packageDir = new File(packageUrl.getFile());
                    if (packageDir.exists() && packageDir.isDirectory()) {
                        processDirectory(packageDir, path);
                    }
                } else if (packageUrl.getProtocol().equals("jar")) {
                    // 处理 JAR 文件
                    String jarPath = packageUrl.getPath().substring(5, packageUrl.getPath().indexOf("!"));
                    JarFile jarFile = new JarFile(jarPath);
                    Enumeration<JarEntry> entries = jarFile.entries();
                    while (entries.hasMoreElements()) {
                        JarEntry entry = entries.nextElement();
                        String entryName = entry.getName();
                        if (entryName.startsWith(packagePath) && entryName.endsWith(".class")) {
                            String className = entryName.replace('/', '.').substring(0, entryName.length() - 6);
                            loadAndRegisterServlet(className);
                        }
                    }
                    jarFile.close();
                }
            }
        } catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    // 处理目录下的所有类文件
    private void processDirectory(File directory, String packageName) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        File[] files = directory.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    processDirectory(file, packageName + "." + file.getName());
                } else if (file.getName().endsWith(".class")) {
                    String className = packageName + '.' + file.getName().substring(0, file.getName().length() - 6);
                    loadAndRegisterServlet(className);
                }
            }
        }
    }

    // 加载并注册 Servlet
    private void loadAndRegisterServlet(String className) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        Class<?> clazz = Class.forName(className);
        if (HttpServlet.class.isAssignableFrom(clazz)) {
            //有@WebServlet注解的 根据注解的urlPatterns属性 注册servlet
            WebServlet annotation = clazz.getAnnotation(WebServlet.class);
            if(annotation==null){
                return;
            }
            String[] urlPatterns = annotation.urlPatterns();
            if(urlPatterns.length>0){
                HttpServlet servlet = (HttpServlet) clazz.newInstance();
                for (String urlPattern : urlPatterns) {
                    Context.urlServletMap.put(urlPattern, servlet);
                    System.out.println("Registered Servlet: " + className + " with URL pattern: " + urlPattern);
                }
            }

        }
    }


    private void deployAppOut(File file, String path) {

        if (file.isDirectory()) {
            for (File f : file.listFiles()) {
                deployAppOut(f, path + file.getName() + "/");
            }
        }
        //不是文件夹 则判断是否是servlet文件
        if (file.getName().endsWith("Servlet.class")) {
            //是servlet文件 则加载到内存中  它本身是i.class文件 所以直接用当前类加载器加载即可
            try {


                //获取类名 先把path用/分隔成数组 然后取后三个 用.连接 然后加上filename的.class去掉 就是类名
                String[] split = path.split("/");
                String tailPath = split[split.length - 3] + "." + split[split.length - 2] + "." + split[split.length - 1]+".";
                String className = tailPath + file.getName().replace(".class", "");

                //加载 类加载器的url split的前三段用/连接
                String url = "/"+split[0] + "/" + split[1] + "/" + split[2];

                File dir = new File(System.getProperty("user.dir") +url);

                URL[] urls = { dir.toURI().toURL() };


                // 使用URLClassLoader加载外部目录中的类
                URLClassLoader classLoader = new URLClassLoader(urls);
                Class<?> clazz = classLoader.loadClass(className);
                if (HttpServlet.class.isAssignableFrom(clazz)) {
                    //有@WebServlet注解的 根据注解的urlPatterns属性 注册servlet
                    WebServlet annotation = clazz.getAnnotation(WebServlet.class);
                    if(annotation==null){
                        return;
                    }
                    String[] urlPatterns = annotation.urlPatterns();
                    if(urlPatterns.length>0){
                        HttpServlet servlet = (HttpServlet) clazz.newInstance();
                        for (String urlPattern : urlPatterns) {
                            Context.urlServletMap.put(urlPattern, servlet);
                            System.out.println("Registered Servlet: " + className + " with URL pattern: " + urlPattern);
                        }
                    }

                }

            }
            catch (Exception e){
                e.printStackTrace();
            }
        }


    }


    //需要连接tcp 这里用socket
    private void start()  {
        try {
            ExecutorService executorService = Executors.newFixedThreadPool(1);

            ServerSocket serverSocket = new ServerSocket(8080);
            while (true) {
                Socket clientSocket = serverSocket.accept();
                executorService.execute(new SocketProcessor(clientSocket));

            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }
}
